<template>
    <n-modal :show="active" :mask-closable="false" :close-on-esc="false" @update:show="(flag:boolean) => (active = flag)">
        <n-card title="选择地点" :style="{ width: '1000px' }">
            <n-space :size="24">
                <n-spin :show="loading" :style="{ width: '700px', height: '600px' }">
                    <div id="maps" :style="{ width: '700px', height: '600px' }"></div>
                </n-spin>
                <n-space vertical justify="space-between" :style="{ width: '225px', height: '600px' }">
                    <n-space vertical>
                        <District v-model:code="areav"></District>
                        <n-select
                            v-model:value="addrv"
                            filterable
                            placeholder="请选择地点或填写关键字查询"
                            :fallback-option="false"
                            :options="poiOpts"
                            :loading="loading"
                            @update:value="onSelectChange"
                            clearable
                            remote
                            :render-label="renderAddrLabel"
                            :render-tag="renderAddrTag"
                            @search="onAddrSearch"
                        />
                    </n-space>
                    <n-space vertical>
                        <n-divider dashed v-if="locs">已选择</n-divider>
                        <n-text depth="3" v-if="locs">{{ areat }}</n-text>
                        <n-text v-if="locs">{{ addrt }}</n-text>
                        <n-divider v-if="locs" dashed></n-divider>

                        <n-space justify="end">
                            <n-button @click="doEnter" type="info" :disabled="!locs">确认</n-button>
                            <n-button @click="() => (active = false)">关闭</n-button>
                        </n-space>
                    </n-space>
                </n-space>
            </n-space>
        </n-card>
    </n-modal>
</template>
<script lang="ts" setup>
import { h, computed, onMounted, ref, watch, shallowRef } from 'vue'

import '@amap/amap-jsapi-types'
import AMapLoader from '@amap/amap-jsapi-loader'

import District from '@/comp/func/District.vue'
import { NSpace, NText } from 'naive-ui'

const { $message: message } = window

const prop = defineProps({
    show: {
        type: Boolean,
        required: true,
    },
    item: {
        type: Object,
        default: {},
    },
})

const emit = defineEmits(['update:show', 'enter'])

const active = computed({
    get: () => prop.show,
    set: val => emit('update:show', val),
})

const areat = ref<number | undefined>(undefined)
const addrt = ref<string | undefined>(undefined)
const locs = ref<string | undefined>(undefined)
const areav = ref<number | undefined>(undefined)
const addrv = ref<string | undefined>(undefined)

const doEnter = () => {
    if (!locs.value) {
        message.warning('请选择地点')
        return
    }
    emit('enter', {
        code: areav.value,
        area: areat.value,
        addr: addrt.value,
        locs: locs.value,
    })
    active.value = false
}

const loading = ref(false)
const handler = ref(false)

watch(areav, (nv, ov) => {
    if (!handler.value) {
        if (nv != ov) {
            map.value.clearMap()
            addrv.value = undefined
            addrt.value = undefined
            locs.value = undefined
            poiOpts.value = []
        }
        map.value.setCity(nv)
    }
})

const poiOpts = ref<any[]>([])

const renderAddrLabel = (opt: any) => {
    return h(
        NSpace,
        { vertical: true, style: { marginBottom: '12px', marginTop: '12px' } },
        {
            default: () => [h(NText, {}, { default: () => opt.label }), h(NText, { depth: 3 }, { default: () => opt.area })],
        }
    )
}

const renderAddrTag = (item: { option: any }) => {
    return h(NText, {}, { default: () => item.option.label })
}

const onSelectChange = (value: string, opt: any) => {
    if (!value) {
        return
    }
    let tip: any = {
        location: {
            lng: parseFloat(opt.value.toString().split(':')[1].split(',')[0]),
            lat: parseFloat(opt.value.toString().split(':')[1].split(',')[1]),
        },
        name: opt.label,
        adcode: opt.value.toString().split(':')[0],
        adtext: opt.area,
    }

    setCurrentMarker(tip)
}

const onAddrSearch = (query: string) => {
    if (!query.length) {
        addrv.value = undefined
        addrt.value = undefined
        locs.value = undefined
        poiOpts.value = []
        map.value.clearMap()
        return
    }
    execSearchPoi(query)
}

const execSearchPoi = (query: string) => {
    loading.value = true
    search.value.setCity(areav.value || '全国')
    search.value.setCityLimit(areav.value ? true : false)
    search.value.search(query, (status: any, result: any) => {
        loading.value = false
        if (status == 'complete' && result.tips) {
            map.value.clearMap()

            poiOpts.value = result.tips
                .filter((tip: any) => tip.id)
                .map((tip: any) => {
                    return {
                        label: tip.name,
                        value: tip.adcode + ':' + tip.location.lng.toFixed(6) + ',' + tip.location.lat.toFixed(6),
                        area: tip.district,
                    }
                })

            let markers = result.tips
                .filter((tip: any) => tip.id)
                .map((tip: any, idx: number) => {
                    let marker = new AMap.Marker({
                        map: map.value,
                        title: tip.name,
                        // icon: `/images/maps/poi-marker-${0 + 1}.png`,
                        position: [tip.location.lng, tip.location.lat],
                        offset: new AMap.Pixel(-13, -30),
                    })
                    marker.setLabel({
                        direction: idx % 2 == 0 ? 'right' : 'left',
                        offset: new AMap.Pixel(idx % 2 == 0 ? 10 : -10, 0),
                        content: `<span>${tip.name}</span>`,
                    })
                    marker.setExtData({
                        location: {
                            lng: tip.location.lng,
                            lat: tip.location.lat,
                        },
                        name: tip.name,
                        adcode: tip.adcode,
                        adtext: tip.district,
                    })

                    marker.on('click', onMarkerClick)
                    return marker
                })
            map.value.add(markers)
            map.value.setFitView()
        }
    })
}

const map: any = shallowRef(null)
const search: any = shallowRef(null)
const geocoder: any = shallowRef(null)
const mapMarker: any = shallowRef(null)

const initMap = () => {
    AMapLoader.load({
        key: 'e51413dde7532ed95e2b2a923dbb9c95',
        version: '2.0',
        plugins: ['AMap.Scale', 'AMap.Geocoder', 'AMap.AutoComplete'],
    })
        .then(AMap => {
            map.value = new AMap.Map('maps', {
                viewMode: '3D',
                zoom: 13,
                resizeEnable: true,
            })

            map.value.on('click', onMapClick)

            AMap.plugin(['AMap.AutoComplete'], () => {
                search.value = new AMap.AutoComplete({})
            })

            AMap.plugin(['AMap.Geocoder'], () => {
                geocoder.value = new AMap.Geocoder({
                    extensions: 'all',
                })
            })
        })
        .catch(() => {})
}

const onMapClick = (e: any) => {
    loading.value = true

    geocoder.value.getAddress([e.lnglat.lng, e.lnglat.lat], (status: any, result: any) => {
        if (status === 'complete' && result.info === 'OK') {
            let tip: any = {
                location: {
                    lng: e.lnglat.lng,
                    lat: e.lnglat.lat,
                },
                name: '',
                adcode: '',
                adtext: '',
            }
            if (result.regeocode.pois && result.regeocode.pois.length > 0) {
                let poi = result.regeocode.pois[0]
                if (poi.distance < 100) {
                    tip.name = poi.name
                } else if (poi.distance < 500) {
                    tip.name = poi.name + '附近'
                }
            }
            let acomp = result.regeocode.addressComponent
            tip.adcode = acomp.adcode
            tip.adtext = acomp.province + acomp.city + acomp.district
            if (!tip.name) {
                if (acomp && acomp.building) {
                    tip.name = acomp.building
                }
            }
            if (!tip.name) {
                tip.name = acomp.street + acomp.streetNumber
            }
            if (!tip.name) {
                tip.name = result.regeocode.formattedAddress.split(acomp.district)[1]
            }
            setCurrentMarker(tip)

            let opts: any[] = poiOpts.value
            opts.splice(0, 0, { label: tip.name, value: tip.adcode + ':' + tip.location.lng.toFixed(6) + ',' + tip.location.lat.toFixed(6) })
            poiOpts.value = opts
        }
        loading.value = false
    })
}

const setCurrentMarker = (tip: any) => {
    handler.value = true
    if (mapMarker.value) {
        mapMarker.value.setMap(null)
        mapMarker.value = null
    }
    map.value.clearMap()

    mapMarker.value = new AMap.Marker({
        map: map.value,
        title: tip.name,
        // icon: `/images/maps/poi-marker-${0 + 1}.png`,
        position: [tip.location.lng, tip.location.lat],
    })

    mapMarker.value.setLabel({
        direction: 'right',
        offset: new AMap.Pixel(10, 0),
        content: `<span>${tip.name}</span>`,
    })
    mapMarker.value.setExtData(tip)

    map.value.add(mapMarker.value)

    map.value.setZoomAndCenter(16, [tip.location.lng, tip.location.lat])

    areav.value = parseInt(tip.adcode)
    areat.value = tip.adtext
    addrv.value = tip.adcode + ':' + tip.location.lng.toFixed(6) + ',' + tip.location.lat.toFixed(6)
    addrt.value = tip.name
    locs.value = tip.location.lng.toFixed(6) + ',' + tip.location.lat.toFixed(6)

    setTimeout(() => {
        handler.value = false
    }, 500)
}

const onMarkerClick = (e: any) => {
    setCurrentMarker(e.target._opts.extData)
}

onMounted(() => {
    initMap()
})
</script>
